<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Basic Operations on Images</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d6/d00/tutorial_py_root.html">OpenCV-Python Tutorials</a></li><li class="navelem"><a class="el" href="../../d7/d16/tutorial_py_table_of_contents_core.html">Core Operations</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Basic Operations on Images </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h2>Goal </h2>
<p>Learn to:</p>
<ul>
<li>Access pixel values and modify them</li>
<li>Access image properties</li>
<li>Set a Region of Interest (ROI)</li>
<li>Split and merge images</li>
</ul>
<p>Almost all the operations in this section are mainly related to Numpy rather than OpenCV. A good knowledge of Numpy is required to write better optimized code with OpenCV.</p>
<p>*( Examples will be shown in a Python terminal, since most of them are just single lines of code )*</p>
<h2>Accessing and Modifying pixel values </h2>
<p>Let's load a color image first: </p><div class="fragment"><div class="line">&gt;&gt;&gt; <span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line">&gt;&gt;&gt; <span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"></div><div class="line">&gt;&gt;&gt; img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>)</div></div><!-- fragment --><p> You can access a pixel value by its row and column coordinates. For BGR image, it returns an array of Blue, Green, Red values. For grayscale image, just corresponding intensity is returned. </p><div class="fragment"><div class="line">&gt;&gt;&gt; px = img[100,100]</div><div class="line">&gt;&gt;&gt; <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>( px )</div><div class="line">[157 166 200]</div><div class="line"></div><div class="line"><span class="comment"># accessing only blue pixel</span></div><div class="line">&gt;&gt;&gt; blue = img[100,100,0]</div><div class="line">&gt;&gt;&gt; <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>( blue )</div><div class="line">157</div></div><!-- fragment --><p> You can modify the pixel values the same way. </p><div class="fragment"><div class="line">&gt;&gt;&gt; img[100,100] = [255,255,255]</div><div class="line">&gt;&gt;&gt; <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>( img[100,100] )</div><div class="line">[255 255 255]</div></div><!-- fragment --><p><b>Warning</b></p>
<p>Numpy is an optimized library for fast array calculations. So simply accessing each and every pixel value and modifying it will be very slow and it is discouraged.</p>
<dl class="section note"><dt>Note</dt><dd>The above method is normally used for selecting a region of an array, say the first 5 rows and last 3 columns. For individual pixel access, the Numpy array methods, array.item() and array.itemset() are considered better. They always return a scalar, however, so if you want to access all the B,G,R values, you will need to call array.item() separately for each value.</dd></dl>
<p>Better pixel accessing and editing method : </p><div class="fragment"><div class="line"><span class="comment"># accessing RED value</span></div><div class="line">&gt;&gt;&gt; img.item(10,10,2)</div><div class="line">59</div><div class="line"></div><div class="line"><span class="comment"># modifying RED value</span></div><div class="line">&gt;&gt;&gt; img.itemset((10,10,2),100)</div><div class="line">&gt;&gt;&gt; img.item(10,10,2)</div><div class="line">100</div></div><!-- fragment --><h2>Accessing Image Properties </h2>
<p>Image properties include number of rows, columns, and channels; type of image data; number of pixels; etc.</p>
<p>The shape of an image is accessed by img.shape. It returns a tuple of the number of rows, columns, and channels (if the image is color): </p><div class="fragment"><div class="line">&gt;&gt;&gt; <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>( img.shape )</div><div class="line">(342, 548, 3)</div></div><!-- fragment --><dl class="section note"><dt>Note</dt><dd>If an image is grayscale, the tuple returned contains only the number of rows and columns, so it is a good method to check whether the loaded image is grayscale or color.</dd></dl>
<p>Total number of pixels is accessed by <code>img.size</code>: </p><div class="fragment"><div class="line">&gt;&gt;&gt; <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>( img.size )</div><div class="line">562248</div></div><!-- fragment --><p> Image datatype is obtained by `img.dtype`: </p><div class="fragment"><div class="line">&gt;&gt;&gt; <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>( img.dtype )</div><div class="line">uint8</div></div><!-- fragment --><dl class="section note"><dt>Note</dt><dd>img.dtype is very important while debugging because a large number of errors in OpenCV-Python code are caused by invalid datatype.</dd></dl>
<h2>Image ROI </h2>
<p>Sometimes, you will have to play with certain regions of images. For eye detection in images, first face detection is done over the entire image. When a face is obtained, we select the face region alone and search for eyes inside it instead of searching the whole image. It improves accuracy (because eyes are always on faces :D ) and performance (because we search in a small area).</p>
<p>ROI is again obtained using Numpy indexing. Here I am selecting the ball and copying it to another region in the image: </p><div class="fragment"><div class="line">&gt;&gt;&gt; ball = img[280:340, 330:390]</div><div class="line">&gt;&gt;&gt; img[273:333, 100:160] = ball</div></div><!-- fragment --><p> Check the results below:</p>
<div class="image">
<img src="../../roi.jpg" alt="roi.jpg"/>
<div class="caption">
image</div></div>
 <h2>Splitting and Merging Image Channels </h2>
<p>Sometimes you will need to work separately on the B,G,R channels of an image. In this case, you need to split the BGR image into single channels. In other cases, you may need to join these individual channels to create a BGR image. You can do this simply by: </p><div class="fragment"><div class="line">&gt;&gt;&gt; b,g,r = <a class="code" href="../../d2/de8/group__core__array.html#ga8027f9deee1e42716be8039e5863fbd9">cv.split</a>(img)</div><div class="line">&gt;&gt;&gt; img = <a class="code" href="../../d2/de8/group__core__array.html#ga61f2f2bde4a0a0154b2333ea504fab1d">cv.merge</a>((b,g,r))</div></div><!-- fragment --><p> Or </p><div class="fragment"><div class="line">&gt;&gt;&gt; b = img[:,:,0]</div></div><!-- fragment --><p> Suppose you want to set all the red pixels to zero - you do not need to split the channels first. Numpy indexing is faster: </p><div class="fragment"><div class="line">&gt;&gt;&gt; img[:,:,2] = 0</div></div><!-- fragment --><p><b>Warning</b></p>
<p><a class="el" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a" title="Divides a multi-channel array into several single-channel arrays. ">cv.split()</a> is a costly operation (in terms of time). So use it only if necessary. Otherwise go for Numpy indexing.</p>
<h2>Making Borders for Images (Padding) </h2>
<p>If you want to create a border around an image, something like a photo frame, you can use <b><a class="el" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36" title="Forms a border around an image. ">cv.copyMakeBorder()</a></b>. But it has more applications for convolution operation, zero padding etc. This function takes following arguments:</p>
<ul>
<li><b>src</b> - input image</li>
<li><b>top</b>, <b>bottom</b>, <b>left</b>, <b>right</b> - border width in number of pixels in corresponding directions</li>
<li><b>borderType</b> - Flag defining what kind of border to be added. It can be following types:<ul>
<li><b><a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5aed2e4346047e265c8c5a6d0276dcd838" title="iiiiii|abcdefgh|iiiiiii with some specified i ">cv.BORDER_CONSTANT</a></b> - Adds a constant colored border. The value should be given as next argument.</li>
<li><b><a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5a815c8a89b7cb206dcba14d11b7560f4b" title="fedcba|abcdefgh|hgfedcb ">cv.BORDER_REFLECT</a></b> - Border will be mirror reflection of the border elements, like this : <em>fedcba|abcdefgh|hgfedcb</em></li>
<li><b><a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5ab3c5a6143d8120b95005fa7105a10bb4" title="gfedcb|abcdefgh|gfedcba ">cv.BORDER_REFLECT_101</a></b> or <b><a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5afe14c13a4ea8b8e3b3ef399013dbae01" title="same as BORDER_REFLECT_101 ">cv.BORDER_DEFAULT</a></b> - Same as above, but with a slight change, like this : <em>gfedcb|abcdefgh|gfedcba</em></li>
<li><b><a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5aa1de4cff95e3377d6d0cbe7569bd4e9f" title="aaaaaa|abcdefgh|hhhhhhh ">cv.BORDER_REPLICATE</a></b> - Last element is replicated throughout, like this: <em>aaaaaa|abcdefgh|hhhhhhh</em></li>
<li><b><a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5a697c1b011884a7c2bdc0e5caf7955661" title="cdefgh|abcdefgh|abcdefg ">cv.BORDER_WRAP</a></b> - Can't explain, it will look like this : <em>cdefgh|abcdefgh|abcdefg</em></li>
</ul>
</li>
<li><b>value</b> - Color of border if border type is <a class="el" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5aed2e4346047e265c8c5a6d0276dcd838" title="iiiiii|abcdefgh|iiiiiii with some specified i ">cv.BORDER_CONSTANT</a></li>
</ul>
<p>Below is a sample code demonstrating all these border types for better understanding: </p><div class="fragment"><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">from</span> matplotlib <span class="keyword">import</span> pyplot <span class="keyword">as</span> plt</div><div class="line"></div><div class="line">BLUE = [255,0,0]</div><div class="line"></div><div class="line">img1 = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;opencv-logo.png&#39;</span>)</div><div class="line"></div><div class="line">replicate = <a class="code" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36">cv.copyMakeBorder</a>(img1,10,10,10,10,cv.BORDER_REPLICATE)</div><div class="line">reflect = <a class="code" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36">cv.copyMakeBorder</a>(img1,10,10,10,10,cv.BORDER_REFLECT)</div><div class="line">reflect101 = <a class="code" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36">cv.copyMakeBorder</a>(img1,10,10,10,10,cv.BORDER_REFLECT_101)</div><div class="line">wrap = <a class="code" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36">cv.copyMakeBorder</a>(img1,10,10,10,10,cv.BORDER_WRAP)</div><div class="line">constant= <a class="code" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36">cv.copyMakeBorder</a>(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)</div><div class="line"></div><div class="line">plt.subplot(231),plt.imshow(img1,<span class="stringliteral">&#39;gray&#39;</span>),plt.title(<span class="stringliteral">&#39;ORIGINAL&#39;</span>)</div><div class="line">plt.subplot(232),plt.imshow(replicate,<span class="stringliteral">&#39;gray&#39;</span>),plt.title(<span class="stringliteral">&#39;REPLICATE&#39;</span>)</div><div class="line">plt.subplot(233),plt.imshow(reflect,<span class="stringliteral">&#39;gray&#39;</span>),plt.title(<span class="stringliteral">&#39;REFLECT&#39;</span>)</div><div class="line">plt.subplot(234),plt.imshow(reflect101,<span class="stringliteral">&#39;gray&#39;</span>),plt.title(<span class="stringliteral">&#39;REFLECT_101&#39;</span>)</div><div class="line">plt.subplot(235),plt.imshow(wrap,<span class="stringliteral">&#39;gray&#39;</span>),plt.title(<span class="stringliteral">&#39;WRAP&#39;</span>)</div><div class="line">plt.subplot(236),plt.imshow(constant,<span class="stringliteral">&#39;gray&#39;</span>),plt.title(<span class="stringliteral">&#39;CONSTANT&#39;</span>)</div><div class="line"></div><div class="line">plt.show()</div></div><!-- fragment --><p> See the result below. (Image is displayed with matplotlib. So RED and BLUE channels will be interchanged):</p>
<div class="image">
<img src="../../border.jpg" alt="border.jpg"/>
<div class="caption">
image</div></div>
 <h2>Additional Resources </h2>
<h2>Exercises </h2>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:37 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
